#include <system.h>
#include <std.h>
#include <fdc.h>
#include <pio.h>
#include <error.h>
#include <type.h>
#include <memory.h>
#include <dint.h>
#include <keyboard.h>
#include <sched.h>
#include <asm.h>
#include <text.h>
#include <irq.h>
#include <ui.h>
#include <vfb.h>

#define MAX_OBJ 25

/*Link condition types*/
#define UNC_LINK 0	//Unconditional link
#define CON_ZERO 1
#define CON_G 2	//Positive
#define CON_L 3	//Negative

#define MAX_PARAM 5
#define MAX_LINKS 3
#define DESC_SZ 256

#define NO_MAP -1

/*The main object structure including a coded function definition for a core object*/

#define LINK_TYPE_DEF 0		//Normal sequential link
#define LINK_TYPE_CONC 1	// A concurrent link

/*This is the link structure. It defines on what condition and to which object the vm should link.*/
/*param_map contains the parameter mappings from the current object to the linked object.*/
struct link	{
	int type;
	int variable;
	int condition;
	int param_map[MAX_PARAM];
	struct obj *link_obj;
};

/*param_type defines the data type of the parameter. If the parameter is an array then 
we make a memory object pointer.*/

struct mem_obj	{
	int el_type;	//Element type
	void *ptr;
	unsigned size;
};

#define TYPE_LONG 0
#define TYPE_SHORT 1
#define TYPE_CHAR 2
#define TYPE_MEM 3	//Memory object pointer
/*In case of memory object pointer take the parameter value as a pointer to the struct mem_obj.*/

struct ovtable	{
	int el_type;
	unsigned size;
	void *ptr;
	char usr_desc[20];
}ovt[


struct obj	{
	int param_type[MAX_PARAM];
	unsigned long params[MAX_PARAM];
	void (*fn)(struct obj *);
	char desc[DESC_SZ];
	struct link links[MAX_LINKS];
	
};

void display_obj(struct obj *x)
{
	printk("\nObject:%x:%s",x,x->desc);
}

/*Displays every member of the object structure */
void display_full_obj(struct obj *x)
{
	int i,j;
	printk("\nObject:%x:%s",x,x->desc);
	for(i=0;i<MAX_PARAM;i++)
		printk("[p%d=%d]",i,x->params[i]);
	for(i=0;i<MAX_LINKS;i++)	{
		if(x->links[i].link_obj)	{
			printk("\nLink%d: type=%d,variable=%d,condition=%d, to:%s",i,x->links[i].type,x->links[i].variable,x->links[i].condition,x->links[i].link_obj->desc);
			printk("map:");
			for(j=0;j<MAX_PARAM;j++)
				printk("%d ",x->links[i].param_map[j]);
		}
	}
}

/*The object registry. All objects created will be registered in this array so that we have
a track of them even if they are not interlinked.*/
struct obj *obj[MAX_OBJ];

/*Console output function. Displays a character in the p0 variable*/
void cono_fn(struct obj *x)
{
	printk("%c",x->params[0]);
}

struct obj cono;	//Console output object
struct obj app;		//Main application object

/*A constructor for an object*/
void init_obj(struct obj *x)
{
	memset(x->params,NULL,MAX_PARAM*sizeof(unsigned long));
	x->fn=NULL;
	memset(x->desc,NULL,DESC_SZ*sizeof(char));
	int i,j;
	for(i=0;i<MAX_LINKS;i++)	{
		x->links[i].type=NULL;
		x->links[i].variable=NULL;
		x->links[i].condition=NULL;
		x->links[i].link_obj=NULL;
		for(j=0;j<MAX_PARAM;j++)	{
			x->links[i].param_map[j]=NO_MAP;
		}
	}
}

/*Finds an object by its description*/
struct obj *get_obj(char *desc)
{
	int i;
	for(i=0;i<MAX_OBJ && strcmp((obj[i])->desc,desc);i++);
	if(i>=MAX_OBJ)	{
		printk("\nObject not found");
		return NULL;
	}
	return obj[i];
}

/*Register an object in the object array as a registry*/
void register_obj(struct obj *x)
{
	int i;
	for(i=0;i<MAX_OBJ && obj[i];i++); //Find a null entry
	obj[i]=x;
}

/*cono is console output and app is the application object to which all newly created
objects should get linked to in order to get executed.*/
void core_init()
{
	memset(obj,0,MAX_OBJ*sizeof(struct obj *));
	init_obj(&cono);
	cono.fn=&cono_fn;
	strcpy(cono.desc,"cono");
	register_obj(&cono);
	display_obj(&cono);
	init_obj(&app);
	strcpy(app.desc,"app");
	register_obj(&app);
	display_obj(&app);
}

/*Create a new empty object. You need to edit the remaining stuff*/
void create_new(char *desc)
{
	struct obj *x;
	x=new(struct obj);
	init_obj(x);
	strcpy(x->desc,desc);
	register_obj(x);
	display_obj(x);
}

#define NUM_SZ 50

/*The editing engine.*/
void edit(struct obj *x)
{
	int c;
	char *p,*v,*idesc=NULL;
	p=(char *)malloc(NUM_SZ);
	v=(char *)malloc(NUM_SZ);
	idesc=(char *)malloc(DESC_SZ);
	display_obj(x);
	printk("\nEdit:\n1.params\n2.desc\n3.Links");
	c=getch();
	switch(c)	{
		case '1': printk("\nEnter param:");
		gets(p);
		printk("Parameter value:%d",x->params[getnumber(p)]);
		printk("\nEnter value:");
		gets(v);
		x->params[getnumber(p)]=getnumber(v);
		break;
		case '2': printk("\nEnter the descriptor:");
		gets(x->desc);
		break;
		case '3': printk("\nEnter the link no.:");
		gets(p);
		int ln;
		ln=getnumber(p);
		printk("\n1.type\n2.variable\n3.condition\n4.Linked object");
		c=getch();
		switch(c)	{
			case '1': printk("\nEnter the type for this link:");
			gets(p);
			x->links[ln].type=getnumber(p);
			break;
			case '2': printk("\nEnter the variable for this link:");
			gets(p);
			x->links[ln].variable=getnumber(p);
			break;
			case '3': printk("\nEnter the condition for this link:");
			gets(p);
			x->links[ln].condition=getnumber(p);
			break;
			case '4': printk("\nEnter the object description you want to link to:");
			do	{	//Find the requested object and link when found.
				gets(idesc);
				if(!strcmp(idesc,"0"))	{
					x->links[ln].link_obj=NULL;
					break;
				}
			} while(!(x->links[ln].link_obj=get_obj(idesc)));
			break;
			default: printk("\nInvalid choice");
		}
		break;
		default: printk("\nInvalid choice");
	}
}

/*This function passes control to control_obj object and starts executing the objects
according to the links. This function should run in background with the editor. In case of
concurrent links this function will create its own instance.*/
static struct obj *control_obj;


void do_map(int link_no,struct obj *src,struct obj *dst)
{
	int i;
	for(i=0;i<MAX_PARAM;i++)	{
		if(src->links[link_no].param_map[i]>NO_MAP)
			dst->params[src->links[link_no].param_map[i]]=src->params[i];
	}
}

void control()
{
	printk("Controlling:app");
	while(1)	{
		if(control_obj->links[0].link_obj)	{
			switch(control_obj->links[0].condition)	{
				case UNC_LINK: do_map(0,control_obj,control_obj->links[0].link_obj);
				control_obj=control_obj->links[0].link_obj;
				/*Now execute a core function of the object if defined as non-zero.*/
				if(control_obj->fn)
					control_obj->fn(control_obj);
				break;
				case CON_ZERO: if(!control_obj->params[control_obj->links[0].variable])	{
					do_map(0,control_obj,control_obj->links[0].link_obj);
					control_obj=control_obj->links[0].link_obj;
					/*Now execute a core function of the object if defined as non-zero.*/
					if(control_obj->fn)
						control_obj->fn(control_obj);
					break;
				}
				case CON_G: if(control_obj->params[control_obj->links[0].variable]>0)	{
					do_map(0,control_obj,control_obj->links[0].link_obj);
					control_obj=control_obj->links[0].link_obj;
					/*Now execute a core function of the object if defined as non-zero.*/
					if(control_obj->fn)
						control_obj->fn(control_obj);
					break;
				}
				case CON_L: if(control_obj->params[control_obj->links[0].variable]<0)	{
					do_map(0,control_obj,control_obj->links[0].link_obj);
					control_obj=control_obj->links[0].link_obj;
					/*Now execute a core function of the object if defined as non-zero.*/
					if(control_obj->fn)
						control_obj->fn(control_obj);
					break;
				}
				default: break;
			}
		} else
			break;
		mdelay(2000);
	}
}

/*this fn is called by 'ls'*/
void display_all()
{
	int i;
	for(i=0;i<MAX_OBJ && obj[i];i++)	{
		display_obj(obj[i]);	//Displays only the description of the object
	}
}

void cl()
{
	char *inp,*cmd,*p,*n;
	struct obj *x=NULL,*lnk=NULL;
	char *constr;
	unsigned long control_id=NULL;
	int cur_link=-1;
	printk("\nObject editing mode:");
	core_init();
	inp=(char *)malloc(256);
	constr=(char *)malloc(256);
	p=(char *)malloc(256);
	cmd=(char *)malloc(64);
	n=(char *)malloc(20);
	while(1)	{
		printk("\n[%s]:",constr,cur_link);
		gets(inp);
		getstringparameter(inp,cmd,' ',0);
		if(!strcmp(cmd,"new"))	{
			getstringparameter(inp,p,' ',1);
			if(!strlen(p))	{
				printk("\nPlease enter a name.");
				continue;
			}
			create_new(p);
		} else if(!strcmp(cmd,"edit"))	{
			if(x)
				edit(x);
		} else if(!strcmp(cmd,"show"))	{
			if(x)
				display_full_obj(get_obj(p));
		} else if(!strcmp(cmd,"open"))	{
			getstringparameter(inp,p,' ',1);
			if(!strlen(p))	{
				printk("\nPlease enter a name.");
				continue;
			}
			x=get_obj(p);
			if(x)
				strcpy(constr,x->desc);
		} else if(!strcmp(cmd,"close"))	{
			printk("\nObject closed.");
			x=NULL;
			strcpy(constr,"");
		} else if(!strcmp(cmd,"link"))	{	//link 0 app
			if(!x)
				continue;
			getstringparameter(inp,p,' ',2);
			getstringparameter(inp,n,' ',1);
			if(strlen(p))	{
				lnk=get_obj(p);
				printk("\nMade link:%s",lnk->desc);
				x->links[getnumber(n)].link_obj=lnk;
			}
			else	{
				printk("\nLink%d:%s",getnumber(n),x->links[getnumber(n)].link_obj->desc);
			}
		} else if(!strcmp(cmd,"control"))	{
			/*Pass control to app object*/
			control_obj=&app;
			control_id=create_process("control",control);
		} else if(!strcmp(cmd,"endcontrol"))	{
			delete_process(control_id);
			control_id=0;
		} else if(!strcmp(cmd,"ls"))	{
			display_all();
		} else if(!strcmp(cmd,"reboot"))	{
			reboot();
		} else if(!strcmp(cmd,"halt"))	{
			halt(0);
		} else	{
			printk("\nCommand not found.");
		}
	}
	halt(0);
}
